#pragma once

typedef enum _SHAPE_COLOR
{
    RED,
    GREEN,
    BLUE,
    WHITE,
    BLACK
}SHAPE_COLOR;

SHAPE_COLOR GetRandomColor()
{
    static bool bTime = false;
    if (!bTime)
    {
        srand((unsigned int)time(nullptr));
        bTime = true;
    }
    return (SHAPE_COLOR)(rand() % 5);           //  0 ~ 4
}

unsigned int GetRandomRadius()
{
    static bool bTime = false;
    if (!bTime)
    {
        srand((unsigned int)time(nullptr));
        bTime = true;
    }
    return (unsigned int)(rand() % 91 + 10);    //  10 ~ 100
}

struct IShape
{
    virtual void Draw() = 0;
};

class CCircle : public IShape
{
private:
    SHAPE_COLOR m_CircleColor;
    unsigned int m_Radius;

    CCircle() { }

public:
    CCircle(SHAPE_COLOR color, unsigned int Radius) : m_CircleColor(color), m_Radius(Radius) {}
    ~CCircle() { }

public:
    void SetRadius(unsigned int Radius) { m_Radius = Radius; }

public:
    virtual void Draw()
    {
        std::cout << "Color: ";
        switch (m_CircleColor)
        {
        case RED:
            std::cout << "Red";
            break;
        case GREEN:
            std::cout << "Green";
            break;
        case BLUE:
            std::cout << "Blue";
            break;
        case WHITE:
            std::cout << "White";
            break;
        case BLACK:
            std::cout << "Black";
            break;
        default:
            break;
        }
        std::cout << ", Radius: " << m_Radius << std::endl;
    }
};

struct IShapeFactory
{
protected:
    virtual IShape* CreateShapeInstance() = 0;

public:
    IShapeFactory() { }
    virtual ~IShapeFactory() { }

    virtual void Draw()
    {
        IShape* lpIShape = CreateShapeInstance();
        lpIShape->Draw();
    }
};

class CCircleFactory : public IShapeFactory
{
private:
    std::map<SHAPE_COLOR, CCircle*> m_CircleMap;

protected:
    virtual IShape* CreateShapeInstance() override 
    { 
        CCircle* lpCircle = nullptr;
        SHAPE_COLOR ShapeColor = GetRandomColor();

        auto it = m_CircleMap.find(ShapeColor);
        if (it == m_CircleMap.end())
        {
            lpCircle = new CCircle(ShapeColor, GetRandomRadius());
            m_CircleMap[ShapeColor] = lpCircle;
        }
        else
        {
            lpCircle = it->second;
            lpCircle->SetRadius(GetRandomRadius());
        }

        return lpCircle;
    }

public:
    CCircleFactory() { }

    virtual ~CCircleFactory()
    {
        for (auto it = m_CircleMap.begin(); it != m_CircleMap.end(); ++it)
        {
            delete (it->second);
        }
        m_CircleMap.clear();
    }
};
